package gobase

import (
	"fmt"
	"regexp"
	"strings"
	"time"
)

type TimeParser struct {
	rg *regexp.Regexp
}

func (p *TimeParser) Init() {
	tokens := []string{":yyyy", "yyyy",
		":yy", "yy",
		":MM", "MM",
		":HH", "HH",
		":hh", "hh",
		":dd", "dd",
		":mm", "mm",
		":ss", "ss",
		":doy",
		":weekday",
		":wn",
		":isown",
		":isowy",
		":HC",
		":hc",
		":m5",
		":m10",
		":m15",
		":m30",
		":s2",
		":s5",
		":s10",
		":s15",
		":ms",
	}
	p.rg = regexp.MustCompile(`(` + strings.Join(tokens, `|`) + `)`)
}

func (p *TimeParser) Parse(s string, now time.Time) string {
	return p.rg.ReplaceAllStringFunc(s, func(match string) string {
		switch match {
		case ":yyyy", "yyyy":
			return now.Format("2006")
		case ":yy", "yy":
			return now.Format("06")
		case ":MM", "MM":
			return now.Format("01")
		case ":dd", "dd":
			return now.Format("02")
		case ":HH", ":hh", "HH", "hh":
			return now.Format("15")
		case ":mm", "mm":
			return now.Format("04")
		case "ss", ":ss":
			return now.Format("05")
		case ":ms", "ms":
			return fmt.Sprintf("%03d", now.Nanosecond()/1e6)
		case "doy", ":doy":
			return fmt.Sprintf("%03d", now.YearDay())
		case "weekday", ":weekday":
			return fmt.Sprintf("%d", now.Weekday())
		case ":wn", "wn":
			week := WeekNumFromJan1Sun(now)
			return fmt.Sprintf("%.2d", week)
		case ":isown":
			_, week := now.ISOWeek()
			return fmt.Sprintf("%.2d", week)
		case ":isowy":
			year, _ := now.ISOWeek()
			return fmt.Sprintf("%.4d", year)
		case ":HC", "HC":
			return toHourChrUpcase(now)
		case ":hc", "hc":
			return toHourChr(now)
		case ":m5", "m5":
			mi := now.Truncate(time.Minute * 5)
			return fmt.Sprintf("%.2d", mi.Minute())
		case ":m10", "m10":
			mi := now.Truncate(time.Minute * 10)
			return fmt.Sprintf("%.2d", mi.Minute())
		case ":m15", "m15":
			mi := now.Truncate(time.Minute * 15)
			return fmt.Sprintf("%.2d", mi.Minute())
		case ":m30", "m30":
			mi := now.Truncate(time.Minute * 30)
			return fmt.Sprintf("%.2d", mi.Minute())
		case ":s5", "s5":
			mi := now.Truncate(time.Second * 5)
			return fmt.Sprintf("%.2d", mi.Second())
		case ":s2", "s2":
			mi := now.Truncate(time.Second * 2)
			return fmt.Sprintf("%.2d", mi.Second())
		case ":s10", "s10":
			mi := now.Truncate(time.Second * 10)
			return fmt.Sprintf("%.2d", mi.Second())
		case ":s15", "s15":
			mi := now.Truncate(time.Second * 15)
			return fmt.Sprintf("%.2d", mi.Second())
		case ":s30", "s30":
			mi := now.Truncate(time.Second * 30)
			return fmt.Sprintf("%.2d", mi.Second())
		default:
			return match
		}
	})
}

var (
	tm TimeParser
)

func init() {
	tm.Init()
}

func ParseTimeFormat(s string, t time.Time) string {
	return tm.Parse(s, t)
}

// A:0时, F(A+6):6时, (A+23):23时,
func toHourChrUpcase(atime time.Time) string {
	h := atime.Hour()
	i := int(rune('A'))
	rval := string(rune(i + h))
	return rval
}

func toHourChr(atime time.Time) string {
	h := atime.Hour()
	i := int(rune('a'))
	rval := string(rune(i + h))
	return rval
}

// 2022-01-01 是星期六
func WeekNumFromJan1Sun(t time.Time) int {
	year := t.Year()
	loc := t.Location()
	jan1 := time.Date(year, 1, 1, 0, 0, 0, 0, loc)

	// 1 月 1 日往前推到周日（weekday=0）
	sundayJan1 := jan1.AddDate(0, 0, -int(jan1.Weekday()))

	// 相差天数
	days := int(t.Sub(sundayJan1).Hours() / 24)
	return days/7 + 1
}
